package com.m1.tzolkin.model.app;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;

import com.m1.tzolkin.ia.IA;
import com.m1.tzolkin.ia.Temple_IA;
import com.m1.tzolkin.model.IAction;
import com.m1.tzolkin.model.IStartingWealth;
import com.m1.tzolkin.model.StartingWealth;
import com.m1.tzolkin.model.TzolkinConstants;
import com.m1.tzolkin.model.board.TZBoard;
import com.m1.tzolkin.model.exceptions.EndOfGameException;
import com.m1.tzolkin.model.exceptions.IllegalWorkerOperationException;
import com.m1.tzolkin.model.exceptions.NoMovedWorkersException;
import com.m1.tzolkin.model.exceptions.NoPlaceException;
import com.m1.tzolkin.model.exceptions.NoWorkerHereException;
import com.m1.tzolkin.model.exceptions.NotEnoughCornException;
import com.m1.tzolkin.model.exceptions.NotEnoughWorkersException;
import com.m1.tzolkin.model.exceptions.WaitingOperationsException;
import com.m1.tzolkin.model.log.Log;
import com.m1.tzolkin.model.players.ITZPlayer;
import com.m1.tzolkin.model.players.TZPlayer;
import com.m1.tzolkin.model.wheels.WheelEnum;


public class Test2 {
	
	private static TZBoard b;
	private static Map<Character, WheelEnum> w;

	/**
	 * @param args
	 * @throws NoMovedWorkersException 
	 * @throws NotEnoughWorkersException 
	 * @throws NoWorkerHereException 
	 * @throws IllegalWorkerOperationException 
	 * @throws NumberFormatException 
	 */
	public static void main(String[] args) throws NumberFormatException, IllegalWorkerOperationException, NoWorkerHereException, NotEnoughWorkersException, NoMovedWorkersException {
		// Initialisation des liens lettre -> roue
		w = new HashMap<Character, WheelEnum>();
		for (WheelEnum e : WheelEnum.values()) {
			w.put(e.name().charAt(0), e);
		}
		// Cr�ation du plateau
		createBoard(createPlayers(new String[] { "Edouard"}));
		// Lancement du jeu
		startGame();
	}
	
	/** GLOBAL ***************************************************************/
	
	private static Collection<ITZPlayer> createPlayers(String[] names) {
		Collection<ITZPlayer> players = new HashSet<ITZPlayer>();
		ITZPlayer p;
		for (int i = 0; i < names.length; ++i) {
			p = new TZPlayer(names[i]);
			players.add(p);
		}
		ITZPlayer stupidIA = new TZPlayer("Bot", true);
		players.add(stupidIA);
		giveStartingWealth(players);
		return players;
	}
	
	private static void createBoard(Collection<ITZPlayer> players) {
		b = new TZBoard(players);
	}
	
	private static void giveStartingWealth(Collection<ITZPlayer> players) {
		IStartingWealth[] tiles = StartingWealth.values();
		int k;
		for (ITZPlayer p : players) {
			for (int i = 0; i < TzolkinConstants.WEALTHS_NB; ++i) {
				do {
					k = (int) (Math.random() * tiles.length);
				} while (tiles[k] == null);
				p.addCard(tiles[k]);
				tiles[k] = null;
			}
		}
	}

	private static void startGame() throws NumberFormatException, IllegalWorkerOperationException, NoWorkerHereException, NotEnoughWorkersException, NoMovedWorkersException {
		_(b);
		Scanner sc = new Scanner(System.in);
		String s;
		char c;
		while (!b.isFinished()) {
			if(b.getCurrentPlayer().isIA()) {
				IA ia = new Temple_IA(b);
				ia.play();
			} else {
				
				s = read(sc);
				// Choix d'action
				if (s.startsWith("DO")) {
					doAction(Integer.parseInt(s.substring(2)) - 1);
					continue;
				}
				c = s.charAt(0);
				// Placement d'ouvrier
				if (w.get(c) != null) {
					place(w.get(c));
					continue;
				}
				switch(c) {
				case 'J': place(); break; // Premier Joueur
				case 'E': endTurn(); break; // Fin du tour
				case '-': remove(w.get(s.charAt(1)), Integer.parseInt(s.substring(2))); break; // Retrait d'ouvrier
				case 'D': try { b.incTurn(Integer.parseInt(s.substring(1))); } catch (Exception e) { e.printStackTrace(); } break; // Avancer de x jours
				}
			}
		}
	}

	/** METHODES ***********************************************************/
	
	private static void doAction(int n) {
		int i = 0;
		Map<IAction, Integer> actions = b.getActions();
		for (IAction a : actions.keySet()) {
			if (i == n) {
				try {
					b.doAction(a);
				} catch (Exception e) {
					e.printStackTrace();
				}
				break;
			}
			++i;
		}
		_(b);
		if (b.getActions().size() > 0) {
			actions = b.getActions();
			_("Actions disponibles : ");
			i = 1;
			for (IAction a : actions.keySet()) {
				//_("  " + i + ". " + getStr(a.toString(b, b.getCurrentPlayer())) + ((actions.get(a) > 0) ? " (-" + actions.get(a) + ")" : ""));
				++i;
			}
		}
	}
	
	private static void endTurn() throws NoMovedWorkersException {
		try {
			b.endTurn();
			_(b);
		} catch (WaitingOperationsException e) {
			e.printStackTrace();
		} catch (EndOfGameException e) {
			e.printStackTrace();
		}
	}
	
	private static void place() throws NotEnoughWorkersException, IllegalWorkerOperationException {
		try {
			b.placeFirstWorker();
			_(b);
		} catch (NoPlaceException e) {
			e.printStackTrace();
		} catch (NotEnoughCornException e) {
			e.printStackTrace();
		}
	}
	
	private static void place(WheelEnum w) throws IllegalWorkerOperationException, NotEnoughWorkersException {
		try {
			int p = b.getWheel(w).getMinimalPosition();
			int pl = b.getPlacedWorkers();
			b.placeWorker(w);
			_(b.getCurrentPlayer().getName() + " pose un ouvrier sur " + w.name() + " pour " + (pl + p) + " ma�s");
			_(b);
		} catch (NoPlaceException e) {
			e.printStackTrace();
		} catch (NotEnoughCornException e) {
			e.printStackTrace();
		}
	}
	
	private static void remove(WheelEnum w, int pos) throws IllegalWorkerOperationException, NoWorkerHereException {
		Map<IAction, Integer> actions = b.takeWorker(w, pos);
		_(b.getCurrentPlayer().getName() + " retire un ouvrier de " + w.name() + "[" + pos + "]");
		_(b);
		_("Actions disponibles : ");
		int i = 1;
		for (IAction a : actions.keySet()) {
			//_("  " + i + ". " + getStr(a.toString(b, b.getCurrentPlayer())) + ((actions.get(a) > 0) ? " (-" + actions.get(a) + ")" : ""));
			++i;
		}
	}
	
	/** OUTILS ***************************************************************/
	
	private static void _(Object s) {
		System.out.println(s);
	}
	
	private static String read(Scanner sc) {
		return sc.next().toUpperCase();
	}
	
	private static String getStr(String[] str) {
		/*StringBuffer sb = new StringBuffer();
		for (String s : str) {
			if (!sb.equals("")) sb.append(" ");
			sb.append(s);
		}
		return sb.toString();*/
		return Log.getTranslation(new Locale("en", "US"), str);
	}

}
